function handles = dXobject_widgetByType(handles, field)
% function dXobject_widgetByType(handles, field)
%
% make a uicontrol widget for editing some field of a dX___ object
%
% Args:
%   handles                 ... handle struct for a dXobjectGUI instance
%       .objectFigure	... parent of all widgets
%       .pObject            ... cell indicating field in ROOT_STRUCT of a dX___ object
%       .widgeRect          ... location in figure to place next widget
%
%   field               ... struct with widget prescriptions
%       .name           ... string containing name of dX___ field
%       .data           ... data in fieldname
%       .safeType       ... string MATLAB class of data in fieldname
%       .userType       ... string user-defined type of fieldname or special flag
%       .range          ... cell containing constraints on field.data
%
% Returns:
%       handles, updated for a new uicontrol widget

% Case on the safeType of field data to determine widget properties.
% The cell {userType} in attrib(2) is either an unsafe data type string
% declared in the definition of a dX___ object, or a special flag used
% for editing a particular cell element/struct field belonging to dX___.

numeric = {'double','single','int8','uint8', ...
    'int16','uint16','int32','uint32','int64','uint64'};

% a row of widgets gets placed inside this rectangle
pos = handles.widgeRect;

switch field.safeType

    case numeric
        % numeric data get either a big edit widget
        % or a text widget and a slider widget

        % pick 'Position' for widget showing numeric field data
        if isempty(field.data)
            % edit widget makes room for new entry
            str = '';
            pos(3:4) = [6, 1.4];
        else
            % edit widget accomodates entire matrix
            str = num2str(field.data,4);
            pos(3:4) = [handles.tab(2)-handles.tab(1), ...
                size(field.data,1)*handles.widgeRect(4)];
        end
        % place edit widget right of fieldname widget
        pos(1) = handles.tab(1);

        if isempty(field.range)

            % edit widget with no range constraint
            uicontrol(handles.objectFigure, ...
                'Style',                'edit', ...
                'Position',             pos, ...
                'HorizontalAlignment',  'left', ...
                'String',               str, ...
                'Tag',                  'numericEdit', ...
                'UserData',             field.data, ...
                'BackgroundColor',      'w', ...
                'Callback',             ...
                {@dXobject_editField, field, handles.dXcopy,handles.sbH});

            % move widgeRect up by a bunch
            handles.widgeRect(2) = handles.widgeRect(2) + pos(4);

        else

            % text widget showing range-constrained value
            twH = uicontrol(handles.objectFigure, ...
                'Style',                'text', ...
                'Position',             pos, ...
                'HorizontalAlignment',  'left', ...
                'String',               field.data, ...
                'Tag',                  'numericText', ...
                'UserData',             field.range, ...
                'BackgroundColor',      [1,1,1]*0.8, ...
                'Callback',             ...
                {@dXobject_editField, field, handles.dXcopy,handles.sbH});

            % make a slider widget to edit field value...

            if size(field.range) == [1,2]
                % ...either continuous values between min and max

                m = min([field.range{:}]);
                M = max([field.range{:}]);

                % step by 1% or 10% of max-min
                step = [1,10]/100;
                callback = {@dXobject_sliderCallback,twH,false};

                val = field.data;

            else

                % ... or indexed elements of field.range

                m = .9; % must be less than M, will round to 1
                M = size(field.range,2) + .1; % symmetry

                % always increment slider by 1 index unit
                step = [1,1]./max((M-1),1);
                callback = {@dXobject_sliderCallback,twH,true};

                val = find([field.range{:}] == field.data);

            end

            % place slider widget in the rightmost
            % 20 characters of figure realestate
            pos([1,3]) = [handles.tab(2)+1, ...
                handles.widgeRect(3)-handles.tab(2)-2];

            uicontrol(handles.objectFigure, ...
                'Style',        'slider', ...
                'Position',     pos, ...
                'Min',          m, ...
                'Max',          M, ...
                'Value',        val, ...
                'SliderStep',   step, ...
                'Callback',     callback);

            % move widgeRect up by one widget
            handles.widgeRect(2) = handles.widgeRect(2) + handles.widgeRect(4);
        end

    case 'logical'
        % logicals--booleans--only need a toggle button

        % position toggle widget right of fieldname
        pos([1,3]) = [handles.tab(1),6];

        uicontrol(handles.objectFigure, ...
            'Style',                'toggleButton', ...
            'Position',             pos, ...
            'String',               field.data, ...
            'Max',                  1, ...
            'Min',                  0, ...
            'Tag',                  'logicalToggle', ...
            'UserData',             field.data, ...
            'Value',                field.data, ...
            'ForegroundColor',      'r', ...
            'Callback',             ...
            {@dXobject_editField, field, handles.dXcopy,handles.sbH});

        % move widgeRect up by one widget
        handles.widgeRect(2) = handles.widgeRect(2) + handles.widgeRect(4);

    case 'char'
        % strings get an edit widget or
        %a text widget and a slider widget

        % pick 'Position' for widget showing string data
        if isempty(field.data)
            % edit widget makes room for new entry
            pos(3:4) = [6, 1.4];
        else
            pos(3:4) = [handles.tab(2)-handles.tab(1), ...
                size(field.data,1)*handles.widgeRect(4)];
        end
        % place edit widget right of fieldname widget
        pos(1) = handles.tab(1);

        if isempty(field.range)
            % edit widget with no range constraint

            if strcmp(field.name, 'taskList')
                % in special case of taskList file, make a button...

                field.userType{1} = 'task';
                
                uicontrol(handles.objectFigure, ...
                    'Style',                'pushbutton', ...
                    'Position',             pos, ...
                    'HorizontalAlignment',  'center', ...
                    'String',               field.data, ...
                    'Tag',                  'taskBrowseButton', ...
                    'UserData',             field.data, ...
                    'Callback',             ...
                    {@dXobject_editField, field, handles.dXcopy,handles.sbH});

            else
                % ...otherwise make an edit
                uicontrol(handles.objectFigure, ...
                    'Style',                'edit', ...
                    'Position',             pos, ...
                    'HorizontalAlignment',  'left', ...
                    'String',               field.data, ...
                    'Tag',                  'stringEdit', ...
                    'UserData',             field.data, ...
                    'BackgroundColor',      [1,.5,1], ...
                    'Callback',             ...
                    {@dXobject_editField, field, handles.dXcopy,handles.sbH});
            end

            % move widgeRect up by a bunch
            handles.widgeRect(2) = handles.widgeRect(2) + pos(4);

        else
            % text widget showing range-constrained value

            twH = uicontrol(handles.objectFigure, ...
                'Style',                'text', ...
                'Position',             pos, ...
                'HorizontalAlignment',  'left', ...
                'String',               field.data, ...
                'Tag',                  'stringText', ...
                'UserData',             field.range, ...
                'BackgroundColor',      [1,.5,1]*0.8, ...
                'Callback',             ...
                {@dXobject_editField, field, handles.dXcopy,handles.sbH});

            % place slider widget  in rightmost
            % 20 characters of figure realestate
            pos([1,3]) = [handles.tab(2)+1, ...
                handles.widgeRect(3)-handles.tab(2)-2];

            % set value of field by index of field.range

            m = .9; % must be less than M, will round to 1
            M = size(field.range,2) + .1; % symmetry

            % always increment slider by 1 index unit
            step = [1,1]./max((M-1),1);
            callback = {@dXobject_sliderCallback,twH,true};

            val = find(strcmp(field.range,field.data),1);

            uicontrol(handles.objectFigure, ...
                'Style',        'slider', ...
                'Position',     pos, ...
                'Min',          m, ...
                'Max',          M, ...
                'Value',        val, ...
                'SliderStep',   step, ...
                'Callback',     callback);

            % move widgeRect up by one widget
            handles.widgeRect(2) = handles.widgeRect(2) + handles.widgeRect(4);
        end

    case 'function_handle'
        % treat function_handle like unconstrained string,
        % but converted string to function_handle and back

        % pick 'Position' for widget showing field.data
        if isempty(field.data)
            % edit field makes room for new entry
            pos(3:4) = [6, 1.4];
        else
            pos(3:4) = [handles.tab(2)-handles.tab(1), ...
                size(field.data,1)*handles.widgeRect(4)];
        end
        % place edit widget right of fieldname widget
        pos(1) = handles.tab(1);

        uicontrol(handles.objectFigure, ...
            'Style',                'edit', ...
            'Position',             pos, ...
            'HorizontalAlignment',  'left', ...
            'String',               func2str(field.data), ...
            'Tag',                  'function_handleEdit', ...
            'UserData',             field.data, ...
            'BackgroundColor',      [1,1,.5], ...
            'Callback',             ...
            {@dXobject_editField, field, handles.dXcopy,handles.sbH});

        % move widgeRect up by a bunch
        handles.widgeRect(2) = handles.widgeRect(2) + pos(4);
end